#ifndef __ming_fyp_render_ResCache_h__
#define __ming_fyp_render_ResCache_h__

//------------------------------------------------------------------------------
// header includes
#include <map>

#include "fyp/core/String.h"
#include "fyp/core/Any.h"
#include "fyp/core/NullType.h"

//------------------------------------------------------------------------------
namespace ming
{
namespace fyp
{
namespace render
{
	//--------------------------------------------------------------------------
	template<class T, class LoadingPolicy>
	class TResCache
	{
	public:
		//------------------------------
		// #cstor & #dstor
		TResCache(LoadingPolicy *loader)
		{
			mLoader = loader;
		}

		~TResCache()
		{
			Map_t::iterator iter;

			for(iter = mElements.begin(); iter != mElements.end(); ++iter)
				mLoader->Unload( iter->second.GetValue() );

			delete mLoader;
		}

		//------------------------------
		// external operations
		T* Load(
			const TStr &filename,
			const Any &params = Any( NullType() ) )
		{
			Map_t::iterator iter = mElements.find(filename);

			if( iter != mElements.end() )
			{
				iter->second.AddRef();
				return iter->second.GetValue();
			}

			T* t = mLoader->Load( C_STR(filename), params );

			if(NULL == t)
				return t;

			mElements.insert( make_pair( filename, Value_t(t) ) );

			return t;
		}

		//------------------------------
		void Unload(T* t)
		{
			Map_t::iterator iter;
			
			for(iter = mElements.begin(); iter != mElements.end(); ++iter)
			{
				if( iter->second.GetValue() == t)
					break;
			}

			if( iter != mElements.end() )
			{
				// decrease ref-count
				iter->second.Release();

				if( iter->second.IsZeroRef() )
				{
					mLoader->Unload( iter->second.GetValue() );
					mElements.erase(iter);
				}
			}
			else
			{
				// todo throw exception
			}
		}

	private:
		//------------------------------
		// internal attributes
		class Value_t
		{
		public:
			Value_t(T *value) : mValue(value), mRefCnt(1)
			{
			}

			T* GetValue() {return mValue;}

			void AddRef() {mRefCnt++;}
			void Release() {mRefCnt--;}
			bool IsZeroRef() const { return (0 == mRefCnt);}

		private:
			size_t mRefCnt;
			T *mValue;
		};
		
		//------------------------------
		typedef std::map<TStr, Value_t> Map_t;
		Map_t mElements;

		LoadingPolicy *mLoader;

		//------------------------------
		// internal operations
	};
	
	//--------------------------------------------------------------------------
}
}
}


#endif	//__ming_fyp_render_ResCache_h__